home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-17 | 39.1 KB | 906 lines | [TEXT/MSWD] |
- Getting started: Setting up the DYNAMO cross-development system:
- <<< Version 3.1 >>>
-
-
- Step 1: Copy the DYNAMO folder onto your Macintosh. Then rename the folder
- to indicate the project.
-
- Step 2: Create a ProDOS disk. It should be initialized at a 4:1 interleave.
- ProDOS should be copied onto it (get the ProDOS file from a bootable ProDOS 8
- disk, or get the P8 file from the System folder of a GS/OS disk and rename it
- to ProDOS on the floppy). The BUILDAPP.SYSTEM and BUILDAPP.TEXT files (found
- in the folder prodos.stuff) should be copied to the ProDOS disk via Apple File
- Exchange or copied with the copy.prodos.stuff script. When copied to the
- ProDOS disk, the filetype/auxtype of BUILDAPP.SYSTEM should be $FF/$0000, and
- the filetype/auxtype of BUILDAPP.TEXT should be $04/$0000.
-
- Step 3: Start MPW by clicking on any of the source files in the project
- directory. Do a full-build of SAMPLE. When prompted, insert the ProDOS disk.
-
- Step 4: Insert the ProDOS disk into the Apple II (or IIGS). Boot it. (Or
- double click on BUILDAPP.SYSTEM from the finder.)
-
- Note that you can build your binary images onto a server. The BUILDAPP.SYSTEM
- launcher can load them from the server, given the correct build script. This
- eliminates the need for a floppy disk completely.
-
-
- You should now be running the DYNAMO sample application. This sample is
- simply an exerciser of the DYNAMO runtime routines. It tests the routines,
- and also the source code demonstrates using the runtime and macro libraries.
-
-
-
- Now, for more detail:
-
-
-
- The BUILDAPP.SYSTEM program allows the developer to build a multiple-segment
- application into one program file, and to launch it simply on the //e.
- Segments are automatically relocated to appropriate banks of memory, and then
- the application is launched starting at any address in any bank chosen.
-
- BUILDAPP.SYSTEM uses a text file as a script for building the application.
- The default name for this text file is BUILDAPP.TEXT. This can be changed by
- modifying the pathname in the program BUILDAPP.SYSTEM. The pathname starts at
- the sixth byte of the file, memory location $2006 if BLOADed. The pathname is
- a pascal string. (This is the standard ProDOS way of giving the launched
- application a pathname.)
-
- To use the BUILDAPP.SYSTEM program, you will need a disk with ProDOS, the
- BUILDAPP.SYSTEM program, a build script file called BUILDAPP.TEXT, and all the
- segments of your application on one disk. This disk is now bootable. When
- the disk is booted, BUILDAPP.SYSTEM will construct a single executable block
- of code starting at address $2000. Then it may or may not prompt you as to
- whether or not you want to save this image. (The “whether or not” is
- configurable.) During development, you will often choose not to save it,
- since it takes just that much longer to get the application executing. Then
- you can test your latest addition or change to your application. To make a
- bootable disk without BUILDAPP.SYSTEM, you just save the application image to
- disk, and then copy the application to a disk with just ProDOS on it. If the
- application name ends with .SYSTEM, and it has a filetype of $FF, you have a
- bootable application.
-
-
- You may wish to develop on one machine, which writes the segments to the
- ProDOS disk, and then just boot the disk on another machine. This saves a lot
- of time booting into your development environment. There is also the
- advantage of always being able to look at the most current source while
- executing the program. You don't need two machines to develop, but it will
- definitely speed up the add/change/test development cycle every programmer
- goes through.
-
-
-
- How the application is build depends on the BUILDAPP.TEXT script file. Here
- is the explanation of this file:
-
- The first line of the build script is the pathname that will be placed at
- $2006 of the application. You may have no need for this, but if you are
- developing a system application, launchers may place a pathname there, and you
- may want a default.
-
- Lines 2-N are for the segments to be loaded. The first field is the mode
- byte. Bits 0-2 of the mode byte indicate what bank of memory the segment
- should be transferred to at execution time.
-
- Bit 0 indicates ROM or language card. Off for ROM, on for language card.
-
- Bit 1 indicates which language card (if bit 0 is on). Off for primary
- language card, on for auxiliary language card.
-
- Bit 2 indicates 1st or 2nd $D000 bank of language card. Which language card
- is still indicated by bit 0 and 1. Off selects the secondary $D000 bank
- ($C083), and on selects the primary $D000 bank ($C08B).
-
- Bit 3 indicates primary or auxiliary 48k. Off for primary, on for auxiliary.
-
- Bit 4 indicates that the auxiliary stack pointer should NOT be initialized.
- If you load a block of code or data into the auxiliary language card, the
- auxiliary stack pointer is initialized to $FF unless you indicate otherwise by
- setting this bit on.
-
- Bit 7 of the mode byte being on indicates the end of the segment list. Bits
- 0-3 still indicate a bank of memory, and the following field indicates the
- launch address within that bank.
-
- The second field is the load address. This is the address the segment will be
- moved to at execution time.
-
- The third field is the name of the segment itself. This can be a full or
- partial pathname.
-
- The next two lines indicate whether you want hex or decimal information
- indicating starting address and total application size.
-
- The next line indicates whether or not you want to be prompted to save the
- file, and if you don’t want to be prompted, what to do instead. To not be
- prompted, the first character of ths line needs to be a Y, N, or Q (or the
- lowercase equivalent). You will be prompted if the first character of this
- line is anything else. (Putting a ? here if you want to be prompted isn’t a
- bad idea. It acts as a placeholder, and is reasonably descriptive.)
-
- The final line indicates the application filetype, auxtype, and filename. The
- application builder will ask if you want the application saved. After the
- file is saved (or not), the application is launched for testing.
-
- NOTE: All numeric fields can be decimal or hex.
-
- The below is a sample build script that was used to make the application
- builder itself.
-
- There is only one segment for this application. The runtime was linked into
- the main code module, generating only one binary code segment.
-
- BUILDAPP.TEXT ;The default script filename.
- 0,$800,BUILD.BIN ;The buildapp application.
- $80,$800 ;Starting address.
- $ ;Display starting address in hex.
- $ ;Display application size in hex.
- N ;Don’t save file -- just launch it.
- $FF,0,BUILDAPP.SYSTEM ;Filetype, auxtype, and filename.
-
- The BUILDAPP.TEXT file can be up to 2045 bytes long.
-
- Bank switching will still have to occur within the application, as necessary.
- There is no getting around that on a //e. BUILDAPP.SYSTEM is to simplify the
- loading and starting of an application, by making it a single, launchable
- file.
-
-
-
- Below are the macros included in the runtime, and their basic usage:
-
- _____________________________________________________________
-
- OPERAND USAGE:
-
- If the operand represents an integer variable or string, then you do not put a
- # in front of it. Variables and strings are always either a ldx literal, or a
- ldy literal, so the # is assumed. When the macro is expanded, the # is put
- there automatically.
-
- If the operand represents a value, then you will need to put a # or an * in
- front of the operand. If you put a # in front of the operand, then it is a
- literal. If you put an * in front, then it uses the value at that address.
- This is similar to the C unary operator *.
-
- If the operand represents a 1-byte value, then you will need to put a < after
- the # or *. This tells the macros to load only the accumulator with a value
- (instead of the accumulator and y-register) and call the low-byte-only entry
- point instead.
-
- An extension has been added to version 3.1. You can now have as many levels
- of indirection as you want. A single * gives you a single level of indirection.
- (Value at, instead of value.) Two *’s in a row gives you two levels of
- indirection. This would be equivalent to a double-dereference in c.
-
- These macros are interfaces for the runtime routines associated with them.
- The runtime routines handle up to 128 integer variables, and up to 256
- strings. The runtime also has multi-dimension array support. The integer
- functions are simple add,sub,mul,div, and others. These others include mass-
- initialization, min, max, print decimal, etc. The string functions are most
- of what is available in AppleSoft, in various forms. The array functions are
- used to define a base pointer to a row of dta within the array, and then to
- index into and out of that row.
-
- The principle of the runtime routines is that the xreg holds a destination
- variable number (for ints: 0-254, for strings: 0-255). All runtimes preserve
- the xreg, therefore, you can do multiple operations to a single variable
- without having to reload the xreg. The values that are used on the xreg
- variable (the source data), is one of 3 forms for integers:
- 1. 1-byte value
- 2. 2-byte value
- 3. 2-byte integer variable.
- 1-byte values are placed in the acc. 2-byte values are placed in the acc,y
- (acc=lo, y=hi). 2-byte integer variables have the variable number placed in
- the yreg. (The yreg is not preserved by the runtime routines.) Once the
- source data is loaded (in acc, acc-y, or y), the proper call to the runtime
- routines is made. The 'proper' routine is based on the type of data the
- source is. (If the source is a variable, and we are adding, the macro will
- call the addvar routine.)
-
- Strings are also referenced by number. There are 3 tables for strings:
- 1. String length table.
- 2. Max string length table.
- 3. Pointer table.
- So, each string takes up four bytes, plus however long the max string length
- is. Having the pointer allows the program to point into memory that was never
- loaded or initialized. This can save time loading the application from disk.
- The string routines will never overwrite the buffer space allocated for them.
- The string will be truncated. So, you can append strings without worry about
- clobbering memory.
-
- Some code using the macros and runtime might look like:
-
- _restore textForBill ;Point at literal text.
- _readstr billStr ;Read text into string.
- _prstr ;Print the string.
- _hexpad #'0' ;Set hex padding to a 0.
- _rtcout #'$' ;Print a $.
- _varcpy bill,val ;Set bill to val.
- _addl ,#5 ;Add 5 to bill.
- (****** or: _add ,<#5 ******)
- _mulvar ,factor ;Multiply bill by factor.
- _vhexout ;Print bill in hex.
- rts
- textForBill dc.b 'Bill''s value in hex is: ',0
-
- We could replace the _restore, _readstr, _prstr, with:
- textForBill _write 'Bill''s value in hex is: ',0
-
- We could still read the text in the _write macro from elsewhere by:
- _restore textForBill+3 ;Point at literal text.
- _readstr billStr ;Read text into string.
-
- The +3 skips the jsr to the write routine (generated by _write). Both the
- _write and _readstr routines stop at a 0. (The _readstr ending character can
- be changed to whatever you want with the _readend macro, but the default stop
- character is a 0.)
-
-
- Below is a list of the macros, and how they are used:
-
-
- _rtreset
- This macro initializes everything necessary in the runtime. This allows a
- resume after the user presses a reset.
-
-
- _hibitchrs
- This macro is used to turn on the hi-bit for characters that are sent to
- rtcout.
-
-
- _lowbitchrs
- This macro is used to turn off the hi-bit for characters that are sent to
- rtcout.
-
-
- _regchrs
- This macro is used to make sure that characters sent to rtcout are used as-is.
- There will be no modification of the hi-bit.
-
-
- _write &op1,&op2,&op3,...
- This macro prints a cstring. You can use as many operands as MPW allows. You
- can continue onto the next line with the line continuation character \. After
- all the operands are processed, the macro places a cstring 0 terminator
- character at the end of the string. This is done automatically. Placing one
- there yourself will define an extra one, which will end up being a BRK
- instruction in your code.
-
-
- _writecr
- This macro prints a carriage return.
-
-
- _wrcstr op
- This macro prints a c string pointed to by the operand.
-
-
- _rtcout op
- This macro prints a character. This character is either already in the acc
- (no operand), or what is described by the operand. The operand can either be
- an absolute or a value in memory.
-
-
- _signed
- This macro sets signed mode. Printing decimal numbers is affected by this.
-
-
- _unsigned
- This macro sets unsigned mode. Printing decimal numbers is affected by this.
-
-
- _chngsgn
- This macro does a two's compliment on the variable. The result is also
- returned in acc,y.
-
-
- _decoutl op
- This macro prints a 1-byte decimal value. This value is either already in the
- acc (no operand), or what is described by the operand. The operand can either
- be an absolute or a value in memory.
-
-
- _vdecout op
- This macro prints a 2-byte decimal value. This value is stored in a variable.
- The variable number is either already in the xreg (no operand), or is
- determined by the operand.
-
-
- _decout op
- This macro prints a 1- or 2-byte decimal value. This value is either already
- in the acc,y (no operand), or what is described by the operand. The operand
- can either be an absolute or a value in memory. This macro optimizes. If the
- operand is an immediate value, and it is indicated to be a 1-byte value (by
- using <), then code is generated only to load the acc and decoutl is called
- instead of decout.
-
-
- _hexpad op
- This macro sets pad mode for hex. The value is either already in the acc (no
- operand), or what is described by the operand. The operand can either be an
- absolute or a value in memory. Printing hex numbers is affected by this.
-
-
- _hexnopad
- This macro sets no pad mode for hex. Printing hex numbers is affected by
- this.
-
-
- _hexoutl op
- This macro prints a 1-byte hex value. This value is either already in the acc
- (no operand), or what is described by the operand. The operand can either be
- an absolute or a value in memory. Since it is only printing a 1-byte value,
- the maximum amount of padding is one character.
-
-
- _vhexout op
- This macro prints a 2-byte hex value. This value is stored in a variable.
- The variable number is either already in the xreg (no operand), or is
- determined by the operand. The maximum amount of padding is three characters.
-
-
- _hexout op
- This macro prints a 2-byte hex value. This value is either already in the
- acc,y (no operand), or what is described by the operand. The operand can
- either be an absolute or a value in memory. The maximum amount of padding is
- three characters.
-
-
- _addvar op1,op2
- This macro adds a variable to the destination variable. If there is no op1,
- then the destination variable number is assumed to be in the xreg. If there
- is no op2, then the source variable number is assumed to be in the yreg. The
- value of the source variable is returned in acc,y.
-
-
- _addl op1,op2
- This macro adds a 1-byte value to the destination variable. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in the acc. The 1-byte value
- is returned in acc. The yreg is set to 0.
-
-
- _add op1,op2
- This macro adds a 2-byte value to the destination variable. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in acc,y. The 2-byte value
- is returned in acc,y. This macro optimizes. If op2 is an immediate value,
- and it is indicated to be a 1-byte value (by using <), then code is generated
- only to load the acc and addconl is called instead of addcon.
-
-
- _subvar op1,op2
- This macro subtracts a variable from the destination variable. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the source variable number is assumed to be in the yreg.
- The value of the source variable is returned in acc,y.
-
-
- _subl op1,op2
- This macro subtracts a 1-byte value from the destination variable. If there
- is no op1, then the destination variable number is assumed to be in the xreg.
- If there is no op2, then the value is assumed to be in the acc. The 1-byte
- value is returned in acc. The yreg is set to 0.
-
-
- _sub op1,op2
- This macro subtracts a 2-byte value from the destination variable. If there
- is no op1, then the destination variable number is assumed to be in the xreg.
- If there is no op2, then the value is assumed to be in acc,y. The 2-byte
- value is returned in acc,y. This macro optimizes. If op2 is an immediate
- value, and it is indicated to be a 1-byte value (by using <), then code is
- generated only to load the acc and subconl is called instead of subcon.
-
-
- _mulvar op1,op2
- This macro multiplies the destination variable by a variable. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the source variable number is assumed to be in the yreg.
- The result of the multiply is also returned in acc,y.
-
-
- _mull op1,op2
- This macro multiplies the destination variable by a 1-byte value. If there is
- no op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in the acc. The result of
- the multiply is also returned in acc,y.
-
-
- _mul op1,op2
- This macro multiplies the destination variable by a 2-byte value. If there is
- no op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in acc,y. The result of the
- multiply is also returned in acc,y. This macro optimizes. If op2 is an
- immediate value, and it is indicated to be a 1-byte value (by using <), then
- code is generated only to load the acc and _mulconl is called instead of
- mulcon.
-
-
- _divvar op1,op2
- This macro divides the destination variable by a variable. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the source variable number is assumed to be in the yreg.
- The remainder from the divide is returned in acc,y.
-
-
- _divl op1,op2
- This macro divides the destination variable by a 1-byte value. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in the acc. The remainder
- from the divide is returned in acc,y.
-
-
- _div op1,op2
- This macro divides the destination variable by a 2-byte value. If there is no
- op1, then the destination variable number is assumed to be in the xreg. If
- there is no op2, then the value is assumed to be in acc,y. The remainder from
- the divide returned in acc,y. This macro optimizes. If op2 is an immediate
- value, and it is indicated to be a 1-byte value (by using <), then code is
- generated only to load the acc and _divconl is called instead of divcon.
-
-
- _var op
- This macro sets the current variable. The current variable is defined by a
- number in the xreg. All runtime functions preserve the xreg, so multiple
- operations can be done to the same variable without having to reload the xreg
- with the variable number.
-
-
- _set0 op
- This macro sets a variable to 0. If there is no op1, then the destination
- variable number is assumed to be in the xreg. The acc is set to 0.
-
-
- _varcpy op1,op2
- This macro sets a variable to another variable. If there is no op1, then the
- destination variable number is assumed to be in the xreg. If there is no op2,
- then the source variable number is assumed to be in the yreg.
-
-
- _setl op1,op2
- This macro sets a variable to a 1-byte value. If there is no op1, then the
- destination variable number is assumed to be in the xreg. If there is no op2,
- then the value is assumed to be in the acc.
-
-
- _set op1,op2
- This macro sets a variable to a 2-byte value. If there is no op1, then the
- destination variable number is assumed to be in the xreg. If there is no op2,
- then the value is assumed to be in acc,y. The 1-byte value is returned in
- acc. The yreg is set to 0. This macro optimizes. If op2 is an immediate
- value, and it is indicated to be a 1-byte value (by using <), then code is
- generated only to load the acc and _setconl is called instead of setcon.
-
-
-
- _vderef op
- This macro uses a variable as a pointer and sets that variable to the value
- to where that pointer currently points. The macro preserves all registers.
- The c equivalent would be (using longs instead if ints):
- long *ptrvar;
- ptrvar = (long *)*ptrvar;
-
-
-
- _setvars op1,op2,op3,op4,...
- This macro sets multiple variables to constant values. The macro is followed
- by as many operands as MPW allows. The line continuation character \ can be
- used. The odd operands are the variables to be set, and the even operands are
- the values they should be set to. Operand1 gets the value of operand 2, and
- so on. The macro automatically terminates the list with a 255 byte. This is
- why 255 is not allowed as a variable number.
-
-
- _minswap op1,op2
- This macro swaps the two variables if the xreg variable is bigger than the
- yreg variable. If there is no op1, then the destination variable number is
- assumed to be in the xreg. If there is no op2, then the source variable
- number is assumed to be in the yreg.
-
-
- _maxswap op1,op2
- This macro swaps the two variables if the xreg variable is smaller than the
- yreg variable. If there is no op1, then the destination variable number is
- assumed to be in the xreg. If there is no op2, then the source variable
- number is assumed to be in the yreg.
-
-
- _vsgncmp op1,op2
- This macro does a signed compare of two variables. The equal status is true
- if the variables are equal. If the xreg variable is greater or equal, then
- the carry is set. If the xreg variable is smaller, then the carry is clear.
- If there is no op1, then the variable number is assumed to be in the xreg. If
- there is no op2, then the variable number is assumed to be in the yreg. Once
- op1 and op2 are loaded into the registers, if necessary, the registers are
- preserved.
-
-
- _vcmp op1,op2
- This macro does an unsigned compare of two variables. The equal status is
- true if the variables are equal. If the xreg variable is greater or equal,
- then the carry is set. If the xreg variable is smaller, then the carry is
- clear. If there is no op1, then the variable number is assumed to be in the
- xreg. If there is no op2, then the variable number is assumed to be in the
- yreg. Once op1 and op2 are loaded into the registers, if necessary, the
- registers are preserved.
-
-
- _sgncmp op1,op2
- This macro works the same as _vsgncmp, except that it compares a variable to a
- constant. Once op1 and op2 are loaded into the registers, if necessary, the
- registers are preserved.
-
-
- _cmp op1,op2
- This macro works the same as _vcmp, except that it compares a variable to a
- constant. All Once op1 and op2 are loaded into the registers, if necessary,
- the registers are preserved.
-
-
- _rndseed op
- This macro is used to seed the random number generator. If there is no op1,
- then the random seed is assumed to be in the acc,y.
-
-
- _random op
- This macro is used to return a random number from 0 to op - 1. If there is no
- op1, then the random number limit is assumed to be in the acc,y.
-
-
- _strval op
- This macro takes the value of a string and returns it in the acc,y. If there
- is no op1, then the string number is assumed to be in the xreg.
-
-
- _midstrval op1,op2
- This macro takes the value of op1 string starting at op2 character and returns
- it in the acc,y. If there is no op1, then the string number is assumed to be
- in the xreg. If there is no op2, then the character number is assumed to be
- in the yreg.
-
-
- _prstr op
- This macro prints the entire string. If there is no op1, then the string
- number is assumed to be in the xreg.
-
-
- _prleftstr op1,op2
- This macro prints op1 string starting at the first character for op2
- characters. If there is no op1, then the string number is assumed to be in
- the xreg. If there is no op2, then the number of characters is assumed to be
- in the acc.
-
-
- _prmidstr op1,op2,op3
- This macro prints op1 string starting at the op2 character for op3 characters.
- If there is no op1, then the string number is assumed to be in the xreg. If
- there is no op2, then the character number is assumed to be in the yreg. If
- there is no op3, then the number of characters is assumed to be in the acc.
-
-
- _leftstrcpy op1,op2,op3
- This macro copies op3 characters from op2 string to op1 string. If there is
- no op1, then the destination string number is assumed to be in the xreg. If
- there is no op2, then the source string number is assumed to be in the yreg.
- If there is no op3, then the number of characters is assumed to be in the acc.
-
-
- _strcpy op1,op2
- This macro copies op2 string to op1 string. If there is no op1, then the
- destination string number is assumed to be in the xreg. If there is no op2,
- then the source string number is assumed to be in the yreg.
-
-
- _midstrcpy op1,op2,op3,op4
- This macro copies op4 characters, starting at op3 character from op2 string to
- op1 string. If there is no op1, then the destination string number is assumed
- to be in the xreg. If there is no op2, then the source string number is
- assumed to be in the yreg. If there is no op3, then the character number is
- assumed to be in the acc. If there is no op4, then all characters to the end
- of the source string will be copied to the destination string. The op4 case
- is the only case where the assumed value is a particular value (#255), instead
- of what is in a register. This is the case because there are only three
- registers.
-
-
- _leftstrcat op1,op2,op3
- This macro concatenates op3 characters of op2 string onto op1 string. If
- there is no op1, then the destination string number is assumed to be in the
- xreg. If there is no op2, then the source string number is assumed to be in
- the yreg. If there is no op3, then the number of characters is assumed to be
- in the acc.
-
-
- _strcat op1,op2
- This macro concatenates op2 string onto op1 string. If there is no op1, then
- the destination string number is assumed to be in the xreg. If there is no
- op2, then the source string number is assumed to be in the yreg.
-
-
- _midstrcat op1,op2,op3,op4
- This macro concatenates op4 characters starting at op3 character from op2
- string onto op1 string. If there is no op1, then the destination string
- number is assumed to be in the xreg. If there is no op2, then the source
- string number is assumed to be in the yreg. If there is no op3, then the
- character number is assumed to be in the acc. If there is no op4, then all
- characters to the end of the source string will be concatenated to the
- destination string. The op4 case is the only case where the assumed value is
- a particular value (#255), instead of what is in a register. This is the case
- because there are only three registers.
-
-
- _litstr op1,op2,op3,...
- This macro works very much like _write, except that the characters are not
- printed. They are copied into the designated string. If there is no
- designated string, then it is assumed that the xreg already holds the string
- number.
-
-
- _strchr op1,op2
- This macro returns the op2th character of op1 string. If there is no op1,
- then the destination string number is assumed to be in the xreg. If there is
- no op2, then the character number is assumed to be in the acc.
-
-
- _strloc op1
- This macro returns the physical location of op1 string in memory. The string
- location is returned in acc,y.If there is no op1, then the destination string
- number is assumed to be in the xreg.
-
-
- _cstr op1,op2,op3,...
- This macro is used to generate a cstring using the same syntax as other
- macros. It works very much like _write and _litstr in the way it handles
- parameters. The only thing that this macro does, however, is define data.
-
-
- _restore op
- This macro sets the read data pointer. If there is no op, then the address
- for reading data is assumed to be in the acc,y.
-
-
- _readint op
- This macro reads an int from the current data pointer and advances the pointer
- by two bytes. If there is no op1, then the destination variable number is
- assumed to be in the xreg.
-
-
- _readstr op
- This macro reads string data into the designated string until the end-of-
- string character is encountered. The data pointer is then set to point after
- this end-of-string character. If there is no op1, then the destination string
- number is assumed to be in the xreg.
-
-
- _readend op
- This macro is used to set the end-of-string character for _readstr. If there
- is no op1, then the _readstr ending character is assumed to be in the acc.
-
-
- The array handling is simple pointer-based storage and retrieval. There is
- also some logic for multiple-dimensioned arrays. This system can handle
- arrays up to four dimensions deep. With a little work, this can be expanded
- to any number. The system allows for easy expansion to more dimensions. It
- works by having the application first give a description of the array. This
- description consists of the location of the array, the size of the elements in
- the array (byte or word), and what size the dimensions are. There are
- actually four pointers into the array area. The first one is always the base
- address. When the base address is first established, all four pointers are
- set to the base address. If you then wish to index into the array, you tell
- the runtime at what point in the array you wish to access for each level of
- subscript. If a subscript is omitted at the beginning of the index list, then
- it is assumed that the pointer for that level is already what you want. If a
- subscript is omitted after the first subscript, then that subscript is assumed
- to be 0.
-
- For example:
- We have a four dimensional array of words, called things, equated to
- address $4000. We would declare the array with the _array macro as
- follows:
- _array #things,w,#3,#4,#5,#6
-
- This line means "use the memory at #things as an array of words that is
- 3 by 4 by 5 by 6 in size." The array handling routines now use this
- information when getting and putting data to the array. The routines
- only keep track of one array. If you wish to switch between two or more
- arrays, you will have to reissue _array commands. The _array command
- does not allocate or protect any memory. It just gets the relevant
- information for the array. Thus, you can switch arrays as often as you
- want. Of course, there is some time overhead in switching, but it is
- rather minimal.
-
- If we wished to get the element things(1,3,4,5), and place it in the
- variable thing, we would do the following:
- _index #1,#3,#4
- _getw thing,#5
-
- The _index macro builds pointers for the array into each level of
- subscript. The _getw macro indexes (using #5) from the lowest level
- pointer, and gets that word and stores it in the variable thing. If we
- then wish to get the element things(1,3,4,4), we would:
- _getw thing,#4
-
- We don't have to recalculate any pointers. They are still intact from
- the above _index macro. If we wish to change any of the subscripts,
- other than the last one, we will have to issue another _index macro.
- Lets say that we want the element things(1,2,0,5). Knowing that the
- previous _index macro got the element things(1,3,4,5), we can minimize
- the pointer math by having the _index macro redo only the data that is
- no longer valid. We would do an _index macro as follows:
- _index ,#2
- _getw thing,#5
-
- The first subscript is the same. Therefore, the pointer for the first
- subscript is correct. The pointer for the second subscript is generated
- from the first (just as the pointer for the first is generated from the
- base address of the array). So, we don't have to mention the first
- subscript again. Not doing so saves code. Once any subscript pointer
- is recalculated, all the lower level pointers are set to that value.
- This means that there is an assumption that all the remaining subscripts
- are zero. If this is indeed the case, they don't have to be mentioned
- either. In this example, the third subscript is zero. So, it doesn't
- have to be mentioned either. This method of separate pointers for
- different levels of the array can be very efficient. It also can be
- confusing. If it is not clear whether you can leave subscripts out,
- don't. It will still work with all of the subscripts, although it will
- be more code than necessary.
-
- There is another form of the _index macro. It is the _vindex macro.
- This is used when the index value is stored in a variable. One
- unfortunate syntax limitation is that you can't mix the two types on one
- line. You still can mix the two types, however, when indexing into an
- array. For example:
- bob = things(color, 3, type, 5)
-
- would be done like:
- _vindex color
- _index ,#3
- _vindex ,,type
- _getw bob,#5
-
-
- The following macros are used to define and access arrays.
-
- _array loc,elesize,op1,op2,op3,op4
- This macro prepares the array handling routines to work on the defined array.
- The operand loc is either the address of the array (when preceded by a #
- sign), or a 2-byte location where the address to the array is stored (when
- preceded by an *). The operand elesize determines the size of the elements in
- the array. The elements can be either bytes or words. The operand elesize
- should be either a b or a w. Operands op1 through op4 describe the dimensions
- of the array. These must be constants. Operands op2 through op4 are
- optional. The array may only be linear, in which case, op2 through op4 would
- have no function. The operand op1 is actually not used. It is just for
- commenting purposes. The array routines do not do any range checking, and all
- that op1 is good for is to determine if the first subscript is out of range.
- You must have an op1, however, as a placeholder. This is to encourage it
- being used, as it is useful when reading the source code.
-
-
- _index op1,op2,op3
- This macro is used to calculate a pointer into the array. There are actually
- four pointers. The first three are used as partial results from previous
- calculations, so that all subscripts don't have to be involved every time
- there is a calculation to determine the specific element of the array. When
- the pointer for op1 is calculated, the resulting offset is added to the base
- array pointer (defined with the _array macro). This is then stored as the
- 2nd, 3rd, and 4th level pointers. If there are no more operands, then the
- effective pointer into the array will be this value. If op2 and op3 were
- zero, then this value would be correct. The assumption in this case is that
- any undeclared subscripts beyond the first one declared are zero. So, if your
- array is only two-dimensional, you would then never declare an op2 or op3, and
- they would therefore never affect the pointer into the array. An interesting
- aside to this is that one array can actually be considered to have a variable
- number of dimensions. Let's say that you have an array that is 10x10x10.
- This array could also be viewed as a 10x100 array. Both have the same number
- of elements. Using the _index macro differently, you could access the array
- either way. For example:
- _index #5
- _getw value,#55
- would work as well as
- _index #5,#5
- _getw value,#5
- This flexibility can be very useful. (It can also be confusing.) If you have
- a case where you know that the first subscript is the same as the last time
- you used the _index (or _vindex) macro, you can choose not to restate that
- subscript. You might even have a situation where the second subscript is the
- same also. In these cases, you can choose to leave those operand fields
- empty. This will produce less code than if you mentioned them. (There is an
- overhead of 7 bytes per index with the _index macro, and an overhead of 5
- bytes with the _vindex macro.)
- The syntax for this would look like: _index ,,#5
- The commas are necessary to indicate that subscripts 1 and 2 are already
- defined, and that you are referring to subscript 3. If the commas were not
- there, the _index macro would assume that the #5 is the first subscript, and
- that subscripts 2 and 3 are zero, or not used at all. This macro optimizes.
- If an operand is an immediate value, and it is indicated to be a 1-byte value
- (by using <), then code is generated only to load the acc and arraylindxN is
- called instead of arrayindxN.
-
-
- _vindex op1,op2,op3
- This macro works just like _index, except that the operands are variables,
- instead of constants or values at a particular memory location. This is
- useful when you want to use variable subscripts.
-
-
- _getb op1,op2
- This macro is used to get a 1-byte value from the array. The operand op2 is
- the right-most subscript in the array. This value can be either a constant,
- or a value in memory. The operand op1 is the variable to store the array
- value into. The low byte of the variable will be set to the value, and the
- hi-byte will be set to zero. This macro optimizes. If op2 is an immediate
- value, and it is indicated to be a 1-byte value (by using <), then code is
- generated only to load the acc and getbytel is called instead of getbyte.
-
-
- _getbl op1,op2
- This macro is used to get a 1-byte value from the array using a 1-byte index.
- The operand op2 is the right-most subscript in the array. This value can be
- either a constant, or a value in memory. The operand op1 is the variable to
- store the array value into. The low byte of the variable will be set to the
- value, and the hi-byte will be set to zero.
-
-
- _vgetb op1,op2
- This macro works just like _getb, except that the operand op2 is a variable.
-
-
- _getw op1,op2
- This macro works just like _getb, except that the value from the array is a
- word, instead of a byte. This macro optimizes. If op2 is an immediate value,
- and it is indicated to be a 1-byte value (by using <), then code is generated
- only to load the acc and getwordl is called instead of getword.
-
-
- _getwl op1,op2
- This macro works just like _getbl, except that the value from the array is a
- word, instead of a byte.
-
-
- _vgetw op1,op2
- This macro works just like _getw, except that the operand op2 is a variable.
-
-
- _putb op1,op2
- This macro places the low byte of the variable op1 into the array at the point
- described by the right-most subscript op2. The operand op2 is either a
- constant, or a location in memory where the subscript is stored. This macro
- optimizes. If op2 is an immediate value, and it is indicated to be a 1-byte
- value (by using <), then code is generated only to load the acc and putbytel
- is called instead of putbyte.
-
-
- _putbl op1,op2
- This macro places the low byte of the variable op1 into the array at the point
- described by the right-most 1-byte subscript op2. The operand op2 is either a
- constant, or a location in memory where the subscript is stored.
-
-
- _vputb op1,op2
- This macro works just like _getb, except that the operand op2 is a variable.
-
-
- _putw op1,op2
- This macro places the variable's value into the array at the point described
- by the right-most subscript op2. The operand op2 is either a constant, or a
- location in memory where the subscript is stored. This macro optimizes. If
- op2 is an immediate value, and it is indicated to be a 1-byte value (by using
- <), then code is generated only to load the acc and putwordl is called instead
- of putword.
-
-
- _putw op1,op2
- This macro places the variable's value into the array at the point described
- by the right-most 1-byte subscript op2. The operand op2 is either a constant,
- or a location in memory where the subscript is stored.
-
-
- _vputw op1,op2
- This macro works just like _getw, except that the operand op2 is a variable.
-
-